package aiservice

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"server/pkg/ginp"
	"server/pkg/mylog"
	"server/pkg/request"
	"server/setting"
	"strings"

	"github.com/gin-gonic/gin"
)

// 在handler中处理数据后调用下面的方法穿给前端
// c.Writer.WriteString(line) // 将每一行直接写入到客户端
// c.Writer.Flush()           // 确保立即发送到客户端
type handlerFunc = func(data *StreamRespData, c *ginp.ContextPro, statusCode string)

type TongyiService struct {
}

// 创建实例
func NewTongyiService() *TongyiService {
	return &TongyiService{}
}

// 使用模型2
func (s *TongyiService) UseApp(config TongyiConfig) (*RespTongyi, error) {
	requestData := map[string]any{
		"input": map[string]any{
			"prompt":    config.Prompt,
			"memory_id": config.AccountId,
		},
		"parameters": map[string]any{},
		"debug":      map[string]any{},
	}
	req := request.NewRequestWithData(config.ApiUrl, request.HttpTypePost, requestData)
	req.SetHeader("Content-Type", "application/json")
	req.SetHeader("Authorization", "Bearer "+setting.TongyiApiKey)
	resp, err := req.Send()
	if err != nil {
		return nil, err
	}
	respData := &RespTongyi{}
	request.ResponseToData(resp, respData)
	return respData, nil
}

// 调用api获取
func (s *TongyiService) UseAppGetText(config TongyiConfig) (string, error) {
	res, err := s.UseApp(config)
	if err != nil {
		return "", err
	} else {
		return res.Output.Text, nil
	}
}

// 流式调用
func (t *TongyiService) UseStream(config TongyiConfig) {
	requestData := map[string]any{
		"input": map[string]any{
			"prompt":    config.Prompt,
			"memory_id": config.AccountId,
		},
		"parameters": map[string]interface{}{
			"incremental_output": true, //增量输出 您需要实时地逐个读取这些片段以获得完整的结果
		},
		"debug": map[string]any{},
	}
	req := request.NewRequestWithData(config.ApiUrl, request.HttpTypePost, requestData)
	req.SetHeader("Content-Type", "application/json")
	req.SetHeader("Authorization", "Bearer "+setting.TongyiApiKey)
	req.SetHeader("X-DashScope-SSE", "enable") //流式输出关键

	resp, err := req.Send()
	if err != nil {
		println(err.Error())
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		fmt.Printf("Request failed with status code: %d\n", resp.StatusCode)
		fmt.Println(string(body))
		return
	}

	reader := bufio.NewReader(resp.Body)
	for {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Printf("Error reading response stream: %v\n", err)
			return
		}
		// 假设每一行都是一个独立的消息事件。
		// SSE消息格式通常为"data: <message>\n\n"。
		// 我们在这里简单打印出来。
		fmt.Print(line)
	}
}

// 流式调用转发给前端
func (t *TongyiService) UseStreamToGin(config TongyiConfig, c *ginp.ContextPro) {
	requestData := map[string]any{
		"input": map[string]any{
			"prompt":    config.Prompt,
			"memory_id": config.AccountId,
		},
		"parameters": map[string]interface{}{
			"incremental_output": true, //增量输出
		},
		"debug": map[string]any{},
	}
	req := request.NewRequestWithData(config.ApiUrl, request.HttpTypePost, requestData)
	req.SetHeader("Content-Type", "application/json")
	req.SetHeader("Authorization", "Bearer "+setting.TongyiApiKey)
	req.SetHeader("X-DashScope-SSE", "enable") //流式输出关键

	resp, err := req.Send()
	if err != nil {
		println(err.Error())
	}
	defer resp.Body.Close()

	// 检查响应状态码。
	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		c.JSON(resp.StatusCode, gin.H{"error": string(body)})
		return
	}

	// 将响应头设置为文本/事件流类型。
	c.Header("Content-Type", "text/event-stream")
	c.Header("Cache-Control", "no-cache")
	c.Header("Connection", "keep-alive")

	// 直接将API响应的body复制到客户端。
	_, err = io.Copy(c.Writer, resp.Body)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to copy response body"})
		return
	}
}

// 流式调用转发给前端
func (t *TongyiService) UseStreamToGinHandler(config TongyiConfig, c *ginp.ContextPro, handler handlerFunc) {
	requestData := map[string]any{
		"input": map[string]any{
			"prompt":    config.Prompt,
			"memory_id": config.AccountId,
		},
		"parameters": map[string]interface{}{
			"incremental_output": true, //增量输出
		},
		"debug": map[string]any{},
	}
	req := request.NewRequestWithData(config.ApiUrl, request.HttpTypePost, requestData)
	req.SetHeader("Content-Type", "application/json")
	req.SetHeader("Authorization", "Bearer "+setting.TongyiApiKey)
	req.SetHeader("X-DashScope-SSE", "enable") //流式输出关键

	resp, err := req.Send()
	if err != nil {
		println(err.Error())
	}
	defer resp.Body.Close()

	// 检查响应状态码。
	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		handler(nil, c, StrRequestError+string(body))
		// c.JSON(resp.StatusCode, gin.H{"error": string(body)})
		return
	}

	// 将响应头设置为文本/事件流类型。
	c.Header("Content-Type", "text/event-stream")
	c.Header("Cache-Control", "no-cache")
	c.Header("Connection", "keep-alive")

	// 用于累积完整的消息体
	var currFullContent string

	reader := bufio.NewReader(resp.Body)
	for {
		sseDataBody, err := reader.ReadString('\n')
		if err == io.EOF {
			handler(nil, c, StrStreamEnd)
			break
		} else if err != nil {
			handler(nil, c, StrError)
			return
		}

		// 累积消息体
		currFullContent += sseDataBody

		// 检查是否是完整的消息体
		if isCompleteMessage(currFullContent) {
			// 解析成结构体*StreamResponseData
			data, err := ParseStreamData(currFullContent)
			if err != nil {
				mylog.Error(fmt.Sprintf("Error parsing stream data: %s", err.Error()))
			}
			if data == nil {
				return
			}

			// 调用handler并传递完整的消息体
			handler(data, c, StrSuccess)

			// 清空 currFullContent 以准备接收新的消息
			currFullContent = ""
		}
	}
}

// ParseStreamData 解析SSE消息中的data部分 返回StreamRespData
func ParseStreamData(data string) (*StreamRespData, error) {
	jsonStr, err := ParseData(data)
	if err != nil {
		return nil, fmt.Errorf("failed to parse data: %w", err)
	}

	var streamData StreamRespData
	err = json.Unmarshal([]byte(jsonStr), &streamData)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal stream data: %w", err)
	}
	return &streamData, nil
}

// ParseData 解析SSE消息中的data部分
func ParseData(dataStr string) (string, error) {
	// 查找 "data:" 的位置
	dataPrefix := "data:"
	startIndex := strings.Index(dataStr, dataPrefix)
	if startIndex == -1 {
		return "", fmt.Errorf("data prefix not found")
	}

	// 提取 JSON 字符串
	jsonStr := strings.TrimSpace(dataStr[startIndex+len(dataPrefix):])
	return jsonStr, nil
}

// isCompleteMessage 检查 currFullContent 是否是完整的消息体
func isCompleteMessage(content string) bool {
	// 检查是否包含完整的 SSE 消息体格式
	return strings.Contains(content, "id:") &&
		strings.Contains(content, "event:") &&
		strings.Contains(content, ":HTTP_STATUS/") &&
		strings.Contains(content, "data:") &&
		strings.HasSuffix(content, "\n\n") // 确保以两个换行符结束
}

// 上传文件
func (t *TongyiService) UploadFile(filePath string) (*http.Response, error) {
	dashscopeApiKey := setting.TongyiApiKey

	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	part, err := writer.CreateFormFile("file", filePath)
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(part, file)
	if err != nil {
		return nil, err
	}

	err = writer.WriteField("purpose", "file-extract")
	if err != nil {
		return nil, err
	}

	err = writer.Close()
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequestWithContext(context.Background(), "POST", setting.ApiUploadFile, body)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", "Bearer "+dashscopeApiKey)
	req.Header.Set("Content-Type", writer.FormDataContentType())

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

// 在结构体定义部分添加 Day 字段
type PlaceInfo struct {
	Name        string  `json:"name"`
	Longitude   float64 `json:"longitude"`
	Latitude    float64 `json:"latitude"`
	Description string  `json:"description"`
	Type        string  `json:"type"`
	TheDay      int     `json:"the_day"`
}

type StreamHandler struct {
	receiveContent string
	lastPosition   int // 记录上次处理到的位置
}

func NewStreamHandler() *StreamHandler {
	return &StreamHandler{
		lastPosition: 0,
	}
}

func (s *StreamHandler) handlerStreamText(streamText string) ([]PlaceInfo, error) {
	s.receiveContent += streamText

	// 查找最后一个完整的地点数组
	var results []PlaceInfo
	content := s.receiveContent[s.lastPosition:]

	// 查找最后一个完整的地点数组 [...]
	start := strings.LastIndex(content, "[\"")
	if start == -1 {
		return nil, nil
	}

	end := strings.Index(content[start:], "]")
	if end == -1 {
		return nil, nil
	}
	end += start

	// 提取最新的地点数组字符串
	placeStr := content[start : end+1]

	// 解析单个地点数组
	var place []interface{}
	if err := json.Unmarshal([]byte(placeStr), &place); err != nil {
		return nil, nil // 数据不完整或格式错误，继续等待
	}

	// 确保数组长度正确（name, longitude, latitude, description, type, day）
	if len(place) != 6 {
		return nil, nil
	}

	// 转换数据类型
	longitude, _ := place[1].(float64)
	latitude, _ := place[2].(float64)
	day, _ := place[5].(float64)

	// 创建 PlaceInfo
	placeInfo := PlaceInfo{
		Name:        place[0].(string),
		Longitude:   longitude,
		Latitude:    latitude,
		Description: place[3].(string),
		Type:        place[4].(string),
		TheDay:      int(day),
	}

	results = append(results, placeInfo)

	// 更新处理位置
	s.lastPosition = end + 1

	return results, nil
}
